package daoImpl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import constants.Constants;
import dao.DAO;

import util.Helper;
import entities.Apartamento;
import entities.Condominio;
import entities.Taxas;
import exceptions.CPFInvalidoException;
import exceptions.CampoVazioException;
import exceptions.DataInvalidaException;
import exceptions.PorcentagemInvalidaException;
import exceptions.RGInvalidoException;

public class DAOImpl implements DAO{

	private static Logger log = Logger.getLogger(DAOImpl.class);

	private static DAOImpl dao = null;

	private DAOImpl(){
	}

	public static DAOImpl getInstance(){
		if(dao == null){
			dao = new DAOImpl();
		}
		return dao;
	}

	@Override
	public boolean loginIsValido(String login, String senha, Connection connection)
	throws CampoVazioException, SQLException {

		log.debug("Inicio do metodo DAOImpl.loginIsValido.");

		if(Constants.EMPTY_STRING.equals(login.trim())){
			throw new CampoVazioException("LOGIN");
		}

		PreparedStatement pstm;
		pstm = connection.prepareStatement(Queries.RECUPERA_LOGIN_SENHA);

		pstm.setString(1, login);
		pstm.setString(2, senha);

		ResultSet rs = pstm.executeQuery();

		if(rs.next()){
			pstm.close();
			return true;
		}
		return false;

	}

	public ArrayList<String> listarApartamentosVagos(Connection connection) throws SQLException{

		log.debug("Inicio do metodo DAOImpl.listarApartamentosVagos.");

		ArrayList<String> retorno = new ArrayList<String>();

		PreparedStatement pstm;

		pstm = connection.prepareStatement(Queries.LISTA_APTOS_VAGOS);

		ResultSet rs = pstm.executeQuery();

		while (rs.next()){
			retorno.add(rs.getString("NUMERO") +" "+ rs.getString("BLOCO"));
		}

		pstm.close();

		return retorno;
	}

	public void cadastrarCategoria(String categoria, boolean subcategoria, Connection connection) throws SQLException, CampoVazioException{

		if(subcategoria){
			log.debug("Inicio do metodo DAOImpl.cadastrarCategoria. Cadastrando a subcategoria < " + categoria + " >.");
		}
		else{
			log.debug("Inicio do metodo DAOImpl.cadastrarCategoria. Cadastrando a categoria < " + categoria + " >.");
		}

		if(Constants.EMPTY_STRING.equals(categoria.trim())){

			if(subcategoria){
				throw new CampoVazioException("SUBCATEGORIA");
			}

			throw new CampoVazioException("CATEGORIA");
		}

		PreparedStatement pstm;

		pstm = connection.prepareStatement(Queries.CADASTRAR_CATEGORIA);

		pstm.setString(1, categoria);
		pstm.setBoolean(2, subcategoria);

		pstm.executeUpdate();

		pstm.close();
	}

	public void cadastrarSubCategoria(String categoria, String subcategoria, Connection connection) throws SQLException, CampoVazioException{

		log.debug("Inicio do metodo DAOImpl.cadastrarSubCategoria. Cadastrando a SubCategoria < " + subcategoria + " >. para categoria < " + categoria + " >");

		if(Constants.EMPTY_STRING.equals(categoria.trim())){
			throw new CampoVazioException("CATEGORIA");
		}
		else if(Constants.EMPTY_STRING.equals(subcategoria.trim())){
			throw new CampoVazioException("SUBCATEGORIA");
		}

		PreparedStatement pstm;

		pstm = connection.prepareStatement(Queries.CADASTRAR_SUB_CATEGORIA);

		pstm.setString(1, categoria);
		pstm.setString(2, subcategoria);

		pstm.executeUpdate();

		pstm.close();
	}



	public String recuperaCPF(String nome, Connection connection) throws SQLException{
		PreparedStatement pstm = connection.prepareStatement(Queries.BUSCA_CPF);
		pstm.setString(1, nome);

		ResultSet rs = pstm.executeQuery();

		if(rs.next()){
			return rs.getString("CPF");
		}

		return null;
	}

	public void atualizaStatusApto(boolean status, String numero, String bloco, Connection connection)
	throws SQLException {

		log.debug("Inicio do metodo DAOImpl.atualizaStatusApto. Atualizando o apartamento de numero < " + numero + " > e bloco < " + bloco + " >");

		PreparedStatement pstm = connection.prepareStatement(Queries.UPDATE_STATUS_APTO);
		pstm.setBoolean(1, status);
		pstm.setString(2, numero);
		pstm.setString(3, bloco);

		pstm.executeUpdate();

	}

	public boolean primeiraExecucao(Connection connection) throws SQLException {

		boolean primeiraExecucao = false;

		log.debug("Inicio do metodo DAOImpl.primeiraExecucao. Verificando  se eh a primeira execucao do modulo!");

		PreparedStatement pstm = connection.prepareStatement(Queries.PRIMEIRA_EXECUCAO);

		ResultSet rs = pstm.executeQuery();

		if(rs.next()){
			primeiraExecucao = (rs.getInt("QNT") == 0);
		}

		if(primeiraExecucao){
			log.debug("O modulo esta sendo executado pela primeira vez!");
		}

		log.debug("Nao eh a primeira vez que o modulo esta sendo executado!");

		return primeiraExecucao;
	}

	public ArrayList<String> listarCategorias(boolean isSubCategoria, Connection connection) throws SQLException {

		log.debug("Inicio do metodo DAOImpl.listarCategorias.");

		ArrayList<String> categorias = new ArrayList<String>();

		PreparedStatement pstm;

		pstm = connection.prepareStatement(Queries.LISTA_CATEGORIAS);

		pstm.setBoolean(1, isSubCategoria);

		ResultSet rs = pstm.executeQuery();

		while (rs.next()){
			categorias.add(rs.getString("CATEGORIA"));
		}

		pstm.close();

		return categorias;
	}

	public Taxas recuperaTaxas(Connection connection) throws SQLException {

		log.debug("Inicio do metodo DAOImpl.recuperaTaxas");

		PreparedStatement pstm = connection.prepareStatement(Queries.RECUPERA_TAXAS);

		ResultSet rs = pstm.executeQuery();

		Taxas taxas = null;

		if(rs.next()){
			taxas = new Taxas();
			taxas.setMultaAluguel(rs.getDouble("MULTAALUGUEL"));
			taxas.setMultaCondominio(rs.getDouble("MULTACONDOMINIO"));
			taxas.setJurosAoDiaAluguel(rs.getDouble("JUROSAODIAALUGUEL"));
			taxas.setJurosAoDiaCondominio(rs.getDouble("JUROSAODIACONDOMINIO"));
			taxas.setTolerancia(rs.getInt("TOLERANCIA"));
		}

		log.debug("As seguinte taxas foram recuperadas: " + Constants.LINE_SEPARATOR + taxas.toString());

		return taxas;

	}

	public Taxas cadastrarTaxas(String multaAlug, String jurosAlug,
			String multaCond, String jurosCond, String tolerancia, Connection connection) throws CampoVazioException,
			PorcentagemInvalidaException, SQLException {

		log.debug("Inicio do metodo DAOImpl.cadastrarTaxas " + Constants.LINE_SEPARATOR +
				"Multa do Aluguel: " + multaAlug + Constants.LINE_SEPARATOR +
				"Juros ao dia do Aluguel: " + jurosAlug + Constants.LINE_SEPARATOR +
				"Multa do Condominio: " + multaCond + Constants.LINE_SEPARATOR +
				"Juros ao dia do Condominio: " + jurosCond + Constants.LINE_SEPARATOR +
				"Tolerancia em dias: " + tolerancia);

		validaCamposCadastroTaxas(multaAlug, jurosAlug, multaCond, jurosCond, tolerancia);

		double multaAluguel = Double.parseDouble(multaAlug) / 100;
		double jurosDiaAluguel = Double.parseDouble(jurosAlug) / 100;
		double multaCondominio = Double.parseDouble(multaCond) / 100;
		double jurosDiaCondominio = Double.parseDouble(jurosCond) / 100;
		int diasToleraveis = Integer.parseInt(tolerancia);

		Taxas taxas = new Taxas();
		taxas.setMultaAluguel(multaAluguel);
		taxas.setJurosAoDiaAluguel(jurosDiaAluguel);
		taxas.setMultaCondominio(multaCondominio);
		taxas.setJurosAoDiaCondominio(jurosDiaCondominio);
		taxas.setTolerancia(diasToleraveis);


		PreparedStatement pstm = connection.prepareStatement(Queries.CADASTRA_TAXAS);

		pstm.setDouble(1, multaCondominio);
		pstm.setDouble(2, multaAluguel);
		pstm.setDouble(3, jurosDiaCondominio);
		pstm.setDouble(4, jurosDiaAluguel);
		pstm.setInt(5, diasToleraveis);

		pstm.executeUpdate();

		return taxas;


	}
	private void validaCamposCadastroTaxas(String multaAlug, String jurosAlug,
			String multaCond, String jurosCond, String tolerancia) throws CampoVazioException, PorcentagemInvalidaException {

		log.debug("Inicio do metdo DAOImpl.validaCamposCadastroTaxas");

		if(null == multaAlug || Constants.EMPTY_STRING.equals(multaAlug)){
			throw new CampoVazioException("MULTA DO ALUGUEL");
		}
		else if(null == jurosAlug || Constants.EMPTY_STRING.equals(jurosAlug)){
			throw new CampoVazioException("JUROS AO DIA DO ALUGUEL");
		}
		else if(null == multaCond || Constants.EMPTY_STRING.equals(multaCond)){
			throw new CampoVazioException("MULTA DO CONDOMINIO");
		}
		else if(null == jurosCond || Constants.EMPTY_STRING.equals(jurosCond)){
			throw new CampoVazioException("JUROS AO DIA DO CONDOMINIO");
		}
		else if(null == tolerancia || Constants.EMPTY_STRING.equals(tolerancia)){
			throw new CampoVazioException("DIAS TOLERAVEIS");
		}

		try{
			Double.parseDouble(multaAlug);
		}catch(NumberFormatException e){
			throw new PorcentagemInvalidaException("MULTA DO ALUGUEL");
		}

		try{
			Double.parseDouble(jurosAlug);
		}catch(NumberFormatException e){
			throw new PorcentagemInvalidaException("JUROS AO DIA DO ALUGUEL");
		}

		try{
			Double.parseDouble(multaCond);
		}catch(NumberFormatException e){
			throw new PorcentagemInvalidaException("MULTA DO CONDOMINIO");
		}

		try{
			Double.parseDouble(jurosCond);
		}catch(NumberFormatException e){
			throw new PorcentagemInvalidaException("JUROS AO DIA DO CONDOMINIO");
		}

		try{
			Integer.parseInt(tolerancia);
		}catch(NumberFormatException e){
			throw new PorcentagemInvalidaException("DIAS TOLERAVEIS");
		}

	}
}